package com.sniper.web.action.admin;

import com.sniper.data.Protocol;
import com.sniper.model.LoginLog;
import com.sniper.mybatis.service.impl.AdminUserService;
import com.sniper.mybatis.service.impl.LoginLogService;
import com.sniper.utils.HttpRequestUtils;
import com.sniper.utils.ValidateUtil;
import com.sniper.web.action.RootController;
import com.sniper.web.action.VerifyController;
import com.sniper.web.utils.UserDetailsUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.Map;

@RequestMapping(value = "${adminPath}")
@Controller
public class AdminLoginController extends RootController {

    /**
     * 如果直接继承root必须写这个
     *
     * @param map
     */
    @ModelAttribute
    @Override
    public void init(Map<String, Object> map) {
        super.init(map);
    }


    /**
     * 登录出错多少次之后启用验证码
     */
    public final static int maxLoginCount = 3;
    public final static int lockLoginCount = 5;

    @Resource
    AdminUserService adminUserService;

    @Resource
    LoginLogService loginLogService;


    @RequestMapping(value = "login", method = RequestMethod.GET)
    public String login(Map<String, Object> map, HttpServletRequest request,
                        @RequestParam(value = "loginError", required = false, defaultValue = "false") Boolean error) {

        //System.out.println(request.getHeader("Referer"));

        if (error) {
            String loginError = messageSource.getMessage("login.error.otherLogin", null, locale);
            map.put("loginError", loginError);
        }

        if (isRobot()) {
            return redirect("/");
        }
        int userLoginNum = 0;
        Cookie userLoginNumCooke = HttpRequestUtils.getCookieValue(Protocol.USER_LOGIN_NUM_KEY, request.getCookies());
        if (ValidateUtil.isValid(userLoginNumCooke)) {
            userLoginNum = Integer.parseInt(userLoginNumCooke.getValue());
        }
        map.put("error ", error);
        map.put("maxLoginCount", maxLoginCount);
        map.put("userLoginNum", userLoginNum);
        return forward("/admin/login/index.ftl", site.getName());
    }

    /**
     * 用户登录
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String login(HttpServletRequest request, Map<String, Object> map, HttpServletResponse response) throws UnsupportedEncodingException {

        if (isRobot()) {
            return redirect("/");
        }

        int userLoginNum = 0;
        String userLoginError = "";
        // 获取用户登录次数
        Cookie userLoginNumCooke = HttpRequestUtils.getCookieValue(Protocol.USER_LOGIN_NUM_KEY, request.getCookies());
        if (ValidateUtil.isValid(userLoginNumCooke)) {
            userLoginNum = Integer.parseInt(userLoginNumCooke.getValue());
        }
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String shaPassword = DigestUtils.sha1Hex(password);

        if (userLoginNum >= maxLoginCount) {
            // 获取HttpSession中的验证码
            String verifyCode = (String) request.getSession(false).getAttribute(VerifyController.VALIDATE_CODE);
            // 获取用户请求表单中输入的验证码
            String submitCode = WebUtils.getCleanParam(request, "verifyCode");
            System.out.println("session:" + verifyCode);
            System.out.println("submit:" + submitCode);
            if (StringUtils.isEmpty(submitCode)
                    || !StringUtils.equals(verifyCode, submitCode.toLowerCase())) {
                userLoginError = "验证码不正确";
                map.put("loginError", userLoginError);
                map.put("loginNum", userLoginNum);
                map.put("maxLoginCount", maxLoginCount);
                return forward("/admin/login/index.ftl", site.getName());
            }
        }


        // 最终用户登录必须是新版
        UsernamePasswordToken token = new UsernamePasswordToken(username, shaPassword);
        if (request.getParameter("rememberMe") != null) {
            token.setRememberMe(true);
        }

        // 获取当前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        try {
            // 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            // 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            // 所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            // System.out.println("对用户[" + username + "]进行登录验证..验证开始");
            currentUser.login(token);
        } catch (UnknownAccountException uae) {
            userLoginError = "未知账户";
            map.put("loginError", userLoginError);
        } catch (IncorrectCredentialsException ice) {
            userLoginError = "密码不正确";
            map.put("loginError", userLoginError);
        } catch (LockedAccountException lae) {
            userLoginError = "账户已锁定";
            map.put("loginError", userLoginError);
        } catch (ExcessiveAttemptsException eae) {
            userLoginError = "用户名或密码错误次数过多";
            map.put("loginError", userLoginError);
        }

        LoginLog log = new LoginLog();
        log.setIp(HttpRequestUtils.getRealIP(request));
        log.setStime(new Date());
        log.setUname(username);
        log.setAgent(request.getHeader("user-agent"));
        // 验证是否登录成功
        if (currentUser.isAuthenticated()) {
            userLoginNum = 0;
            Cookie cookie = new Cookie(Protocol.USER_LOGIN_NUM_KEY, String.valueOf(userLoginNum));
            response.addCookie(cookie);
            log.setMessage("Success");
            log.setPwd("");
            loginLogService.insert(log);
            String backUrl = (String) request.getSession().getAttribute(Protocol.LOGIN_BACK_URL);
            if (backUrl != null) {
                return UrlBasedViewResolver.REDIRECT_URL_PREFIX + URLDecoder.decode(backUrl, "utf-8");
            }
            return UrlBasedViewResolver.REDIRECT_URL_PREFIX + adminPath + "/";
        } else {
            token.clear();
            userLoginNum++;
            Cookie cookie = new Cookie(Protocol.USER_LOGIN_NUM_KEY, String.valueOf(userLoginNum));
            response.addCookie(cookie);
            log.setMessage(userLoginError);
            log.setPwd(Base64.encodeBase64String(password.getBytes()));
            loginLogService.insert(log);
        }
        map.put("maxLoginCount", maxLoginCount);
        map.put("loginNum", userLoginNum);
        return forward("/admin/login/index.ftl", site.getName());
    }

    /**
     * 用户登出
     */
    @RequestMapping("logout")
    public String logout() {
        UserDetailsUtils detailsUtils = new UserDetailsUtils();
        detailsUtils.logout();
        return redirect("/");
    }
}